package com.twilight.SofaStream;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;

import com.twilight.SofaStream.R;

import android.app.Activity;
import android.app.ProgressDialog;
import android.media.MediaPlayer;
import android.net.Uri;
import android.net.Uri.Builder;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.StatFs;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Handler;
import android.preference.PreferenceManager;

public class ViewEpisode extends Activity {
	
	private RSSItem mArticle;
	private RSSFeed mFeed;
	private ImageButton mPlayButton, mPauseButton, mBackButton, mForwardButton;
	private SeekBar mPlaybackBar;
	private ProgressBar mDownloadProgress;
	private TextView mDownloadStatus, mCurrentText, mTotalText;
	private LinearLayout mDownloadRow, mControlsRow;
	private IPlayerService mPlayerService;
	private IDownloadService mDownloadService;

	
    Handler mUpdateHandler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
				case 0:
					//Deal with downloads
				case 1:
					switch (msg.arg1) {
						case PlayerService.PREPARED:
							try {
								mPlayerService.startTrack();
								markTrackListened();
								//mPreparing.setVisibility(View.GONE);
								showTrackStatus();
								showPlaying();
							} catch (RemoteException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							break;
						case PlayerService.UPDATE:
							updateProgress(msg.arg2);
							break;
						case PlayerService.ERROR:
							//Toast.makeText(ViewEpisode.this, String.format("Error code from Media Player %d", msg.arg2), Toast.LENGTH_SHORT).show();
							Log.d("SofaStream", String.format("Error code from Media Player %d", msg.arg2));
							break;
						case PlayerService.BUFFERING:
							mPlaybackBar.setSecondaryProgress(msg.arg2);
							break;
						case PlayerService.COMPLETION:
				    		mControlsRow.setVisibility(View.GONE);
							break;
					}
				default:
	                super.handleMessage(msg);
			}
		}
    };
	
	IPlayerServiceCallback mPlayerUpdateCallback = new IPlayerServiceCallback.Stub() {
		public void update(int type, int value) {
			mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(1, type, value));
		}
	};
	ServiceConnection mPlayerConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder service) {
            mPlayerService = IPlayerService.Stub.asInterface(service);
            try {
				mPlayerService.registerCallback(mPlayerUpdateCallback);
				if (mPlayerService.isActive()) {
					//initialiseControls();
					showTrackStatus();
				}
	        	showPlaying();
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		public void onServiceDisconnected(ComponentName className) {
			try {
				mPlayerService.unregisterCallback(mPlayerUpdateCallback);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            mPlayerService = null;
		}
	};
	IDownloadServiceCallback mDownloadUpdateCallback = new IDownloadServiceCallback.Stub() {
		public void update(int type, long id, int progress)  {
			mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(0, id));
		}
	};
	ServiceConnection mDownloadConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder service) {
            mDownloadService = IDownloadService.Stub.asInterface(service);
//	            try {
//					mDownloadService.registerCallback(mUpdateCallback);
//				} catch (RemoteException e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				}
		}
		public void onServiceDisconnected(ComponentName className) {
			try {
				mDownloadService.unregisterCallback(mDownloadUpdateCallback);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            mDownloadService = null;
		}
	};

	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.episode_view);
        collectEpisode();
		TextView label = (TextView) findViewById(R.id.EpisodeLabel);
		label.setText(mArticle.title);
		label.setOnClickListener(new 
			OnClickListener() {
				public void onClick(View v) {
					startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(mArticle.url.toString())));
				}			
			}
		);
		TextView body = (TextView) findViewById(R.id.EpisodeContent);
		body.setText(mArticle.text);
		mPlayButton = (ImageButton) findViewById(R.id.play);
		mPauseButton = (ImageButton) findViewById(R.id.pause);
		mBackButton = (ImageButton) findViewById(R.id.rew);
		mForwardButton = (ImageButton) findViewById(R.id.ffwd);
		mPlayButton.setOnClickListener(mPlayListener);
		mPauseButton.setOnClickListener(mPauseListener);
		mBackButton.setOnClickListener(mBackListener);
		mForwardButton.setOnClickListener(mForwardListener);
		mDownloadProgress = (ProgressBar) findViewById(R.id.DownloadProgress);
		mPlaybackBar = (SeekBar) findViewById(R.id.mediacontroller_progress);
		mCurrentText = (TextView) findViewById(R.id.time_current);
		mTotalText = (TextView) findViewById(R.id.time);
		mPlaybackBar.setOnSeekBarChangeListener(PlaybackBarChangedListener);
		mControlsRow = (LinearLayout) findViewById(R.id.ControlsRow);
		startService(new Intent(this, PlayerService.class));
		bindService(new Intent(this, PlayerService.class), mPlayerConnection, BIND_AUTO_CREATE);
		startService(new Intent(this, DownloadService.class));
		bindService(new Intent(this, DownloadService.class), mDownloadConnection, BIND_AUTO_CREATE);
    }

    public void onRestart() {
    	super.onRestart();
    	showPlaying();
    }
    
    public void onDestroy() {
    	unbindService(mPlayerConnection);
    	unbindService(mDownloadConnection);
    	super.onDestroy();
    }

    private void collectEpisode() {
        String id = extractEpisodeId();
		RSSDB db = new RSSDB(this);
		mArticle = db.getArticle(Long.decode(id));
		mFeed = db.getFeed(mArticle.feedId);
    }
    private String extractEpisodeId() {
        Intent i = getIntent();
        Uri u = i.getData();
    	return u.getSchemeSpecificPart();
    }
    
    private SeekBar.OnSeekBarChangeListener PlaybackBarChangedListener = new SeekBar.OnSeekBarChangeListener() {
    	private Boolean mPlayFlag;
		public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
			try {
				if (fromUser) mPlayerService.seekTrack(progress);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		public void onStartTrackingTouch(SeekBar seekBar) {
			try {
				if (mPlayerService.isPlaying()) { 
					mPlayerService.pauseTrack();
					mPlayFlag = true;
				} else {
					mPlayFlag = false;
				}
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}			
		}

		public void onStopTrackingTouch(SeekBar seekBar) {
			try {
				if (mPlayFlag) mPlayerService.startTrack();
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
    };

    private void showTrackStatus () throws RemoteException {
		int duration = mPlayerService.getDuration();
		int progress = mPlayerService.getCurrentPosition();
		mTotalText.setText(buildTime(duration));
		mPlaybackBar.setMax(duration);
		mCurrentText.setText(buildTime(progress));
		mPlaybackBar.setProgress(progress);
		mControlsRow.setVisibility(View.VISIBLE);
    }
    
    private void initialiseControls() {
		mTotalText.setText(buildTime(0));
		mCurrentText.setText(buildTime(0));
		mPlaybackBar.setProgress(0);
		mPlaybackBar.setMax(1000);
		showPlaying();
		mControlsRow.setVisibility(View.VISIBLE);
    }
    
    private void showPlaying() {
    	try {
			if (mPlayerService != null && mPlayerService.isPlaying()) {
				mPlayButton.setVisibility(View.GONE);
				mPauseButton.setVisibility(View.VISIBLE);
			} else {
				mPlayButton.setVisibility(View.VISIBLE);
				mPauseButton.setVisibility(View.GONE);
			}
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    private OnClickListener mBackListener = new OnClickListener() {
		public void onClick(View v) {
			try {
				mPlayerService.seekTrack(mPlayerService.getCurrentPosition() - 4000);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
    };

    private OnClickListener mForwardListener = new OnClickListener() {
		public void onClick(View v) {
			try {
				mPlayerService.seekTrack(mPlayerService.getCurrentPosition() + 4000);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
    };

    private OnClickListener mPlayListener = new OnClickListener() {
		public void onClick(View v) {
			startPlayback();
		}
    };

    private OnClickListener mPauseListener = new OnClickListener() {
		public void onClick(View v) {
			pausePlayback();
		}
    };
    
    private void startPlayback() {
		try {
			mPlayerService.startTrack();
			showPlaying();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    private void pausePlayback() {
		try {
			mPlayerService.pauseTrack();
			showPlaying();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

    private void markTrackListened() {
    	RSSDB db = new RSSDB(this);
    	ContentValues content = new ContentValues();
    	content.put("listened", true);
    	db.updateArticle(mArticle.id, content);
    }

    //Indices of menu items:
    int download_episode = 0;
    int play_downloaded = 1;
    int stop_download = 2; 
    int delete_downloaded = 3;
    int stream_episode = 4;
	int stop_track = 5;
	int mark_listened = 6;
	int mark_new = 7;
    public boolean onCreateOptionsMenu(Menu menu) {
    	MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.episode_menu, menu);
        return true;
    }

    public boolean onPrepareOptionsMenu(Menu menu) {
    	for (int i = 0; i < menu.size(); i++) menu.getItem(i).setVisible(false);
        if (mArticle.listened) {
        	menu.getItem(mark_new).setVisible(true);
        } else {
        	menu.getItem(mark_listened).setVisible(true);
        }
        if (mArticle.downloadstate == RSSItem.downloadstates.UNDOWNLOADED) {
        	menu.getItem(download_episode).setVisible(true);
        }
        if (mArticle.downloadstate == RSSItem.downloadstates.DOWNLOADED) {
        	menu.getItem(delete_downloaded).setVisible(true);
        }
        if (mArticle.downloadstate == RSSItem.downloadstates.DOWNLOADING || mArticle.downloadstate == RSSItem.downloadstates.QUEUED) {
        	menu.getItem(stop_download).setVisible(true);
        }
        if (mArticle.downloadstate == RSSItem.downloadstates.DOWNLOADED || mArticle.downloadstate == RSSItem.downloadstates.FAILED) {
        	menu.getItem(delete_downloaded).setVisible(true);
        }
        try {
			if (mPlayerService.isActive()) {
				menu.getItem(stop_track).setVisible(true);
			} else {
				if (!mFeed.secure)
					menu.getItem(stream_episode).setVisible(true);
		        if (mArticle.downloadstate == RSSItem.downloadstates.DOWNLOADED) {
		        	menu.getItem(play_downloaded).setVisible(true);
		        }
			}
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	return true;
    }

	public boolean onOptionsItemSelected(MenuItem item) {
        RSSDB db = new RSSDB(this);
		ContentValues values = new ContentValues();
		switch (item.getItemId()) {
			case R.id.mark_listened:
				values.put("listened", true);
				db.updateArticle(mArticle.id, values);
				break;
			case R.id.mark_new:
				values.put("listened", false);
				db.updateArticle(mArticle.id, values);
				break;
			case R.id.stream_episode:
				try {
					Log.d("SofaStream", mArticle.toString());
					boolean result = mPlayerService.remoteTrack(mArticle.id);
					if (!result) {
						Toast.makeText(ViewEpisode.this, mPlayerService.getError(), Toast.LENGTH_LONG).show();
					} else {
						Toast.makeText(this, getResources().getString(R.string.connecting_to_server), Toast.LENGTH_LONG).show();
					}
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (SecurityException e) {
					e.printStackTrace();
				} catch (IllegalStateException e) {
					e.printStackTrace();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
				Log.d("SofaStream", "Started streaming");
				break;
			case R.id.play_downloaded:
				try {
					Log.d("SofaStream", mArticle.toString());
					boolean result = mPlayerService.localTrack(mArticle.id);
					if (!result) {
						Toast.makeText(ViewEpisode.this, mPlayerService.getError(), Toast.LENGTH_LONG).show();
//					} else {
//						Toast.makeText(this, "Connecting to server...", Toast.LENGTH_LONG).show();
					}
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (SecurityException e) {
					e.printStackTrace();
				} catch (IllegalStateException e) {
					e.printStackTrace();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
				Log.d("SofaStream", "Started streaming");
				break;
			case R.id.stop_track:
	    		try {
	    			mPlayerService.stopTrack();
		    		mControlsRow.setVisibility(View.GONE);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			case R.id.download_episode:
	    		//mDownloadStatus.setText("Queuing download...");
	    		try {
					boolean result = mDownloadService.download(mArticle.id);
					if (!result) Toast.makeText(ViewEpisode.this, mDownloadService.getError(), Toast.LENGTH_LONG).show();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
				break;
			case R.id.stop_download:
	    		try {
					boolean result = mDownloadService.stop_download(mArticle.id);
					if (!result) Toast.makeText(ViewEpisode.this, mDownloadService.getError(), Toast.LENGTH_LONG).show();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
				break;
			case R.id.delete_downloaded:
	    		try {
	    			if (mPlayerService.isActive() && !mPlayerService.isRemote()) {
	    				Toast.makeText(ViewEpisode.this, getResources().getString(R.string.stop_before_deleting), Toast.LENGTH_LONG).show();
	    			} else {
						boolean result = mDownloadService.delete_download(mArticle.id);
						if (!result) Toast.makeText(ViewEpisode.this, mDownloadService.getError(), Toast.LENGTH_LONG).show();
	    			}
				} catch (RemoteException e) {
					e.printStackTrace();
				}
				break;
			default:
					return super.onContextItemSelected(item);
		}
		collectEpisode();
		return true;
	}
    
    private void updateProgress(int progress) {
		mPlaybackBar.setProgress(progress);
		mCurrentText.setText(buildTime(progress));

    }
    private String buildTime(int time) {
    	int seconds = time / 1000;
    	int sec = seconds % 60;
    	int minutes = seconds / 60;
    	int min = minutes % 60;
    	int hours = minutes / 60;
    	int hur = hours % 24;
    	
//    	if (time < 60 * 60 * 1000) { // If time is less than an hour... 
//    		return String.format("%02d:%02d", min, sec);
//    	} else {
    		return String.format("%d:%02d:%02d", hur, min, sec);
//    	}
    }
}


